﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using AutoMapper;
using IdentityServer4.Models;
using K9Admin.Remoting;
using K9Nano.Application.MultiTenancy;
using K9Nano.Application.Organization.Dto;
using K9Nano.Web.Accounts.Dto;
using Entities = IdentityServer4.EntityFramework.Entities;
using Models = IdentityServer4.Models;

namespace K9Nano.Admin
{
    public class MapperProfile : Profile
    {
        public MapperProfile()
        {
            #region OU

            CreateMap<OrganizationUnitCreateRequest, OrganizationUnitCreateInput>();
            CreateMap<OrganizationUnitUpdateRequest, OrganizationUnitUpdateInput>()
                .ForMember(x => x.Id,
                    m => m.MapFrom(a => string.IsNullOrWhiteSpace(a.Id) ? (Guid?)null : Guid.Parse(a.Id)));

            #endregion

            #region User

            CreateMap<UserCreateRequest, UserCreateInput>();
            CreateMap<UserRoleEditRequest, UserRoleEditInput>();
            CreateMap<UserEditRequest, UserEditInput>();
            CreateMap<UserWithClientsRequest, UserWithClientsInput>();

            #endregion

            #region MultiTenancy

            CreateMap<TenantCreateRequest, TenantCreateInput>();

            #endregion

            #region IdSvr4
            CreateMap<Entities.ClientProperty, KeyValuePair<string, string>>()
               .ReverseMap();

            CreateMap<Entities.Client, Models.Client>()
                .ForMember(dest => dest.ProtocolType, opt => opt.Condition(srs => srs != null))
                .ForMember(x => x.AllowedIdentityTokenSigningAlgorithms, opts => opts.ConvertUsing(AllowedSigningAlgorithmsConverter.Converter, x => x.AllowedIdentityTokenSigningAlgorithms))
                .ReverseMap()
                .ForMember(x => x.AllowedIdentityTokenSigningAlgorithms, opts => opts.ConvertUsing(AllowedSigningAlgorithmsConverter.Converter, x => x.AllowedIdentityTokenSigningAlgorithms));

            CreateMap<Entities.ClientCorsOrigin, string>()
                .ConstructUsing(src => src.Origin)
                .ReverseMap()
                .ForMember(dest => dest.Origin, opt => opt.MapFrom(src => src));

            CreateMap<Entities.ClientIdPRestriction, string>()
                .ConstructUsing(src => src.Provider)
                .ReverseMap()
                .ForMember(dest => dest.Provider, opt => opt.MapFrom(src => src));

            CreateMap<Entities.ClientClaim, ClientClaim>(MemberList.None)
                .ConstructUsing(src => new ClientClaim(src.Type, src.Value, ClaimValueTypes.String))
                .ReverseMap();

            CreateMap<Entities.ClientScope, string>()
                .ConstructUsing(src => src.Scope)
                .ReverseMap()
                .ForMember(dest => dest.Scope, opt => opt.MapFrom(src => src));

            CreateMap<Entities.ClientPostLogoutRedirectUri, string>()
                .ConstructUsing(src => src.PostLogoutRedirectUri)
                .ReverseMap()
                .ForMember(dest => dest.PostLogoutRedirectUri, opt => opt.MapFrom(src => src));

            CreateMap<Entities.ClientRedirectUri, string>()
                .ConstructUsing(src => src.RedirectUri)
                .ReverseMap()
                .ForMember(dest => dest.RedirectUri, opt => opt.MapFrom(src => src));

            CreateMap<Entities.ClientGrantType, string>()
                .ConstructUsing(src => src.GrantType)
                .ReverseMap()
                .ForMember(dest => dest.GrantType, opt => opt.MapFrom(src => src));

            CreateMap<Entities.ClientSecret, Models.Secret>(MemberList.Destination)
                .ForMember(dest => dest.Type, opt => opt.Condition(srs => srs != null))
                .ReverseMap();


            #endregion
        }

        class AllowedSigningAlgorithmsConverter :
            IValueConverter<ICollection<string>, string>,
            IValueConverter<string, ICollection<string>>
        {
            public static AllowedSigningAlgorithmsConverter Converter = new AllowedSigningAlgorithmsConverter();

            public string Convert(ICollection<string> sourceMember, ResolutionContext context)
            {
                if (sourceMember == null || !sourceMember.Any())
                {
                    return null;
                }
                return sourceMember.Aggregate((x, y) => $"{x},{y}");
            }

            public ICollection<string> Convert(string sourceMember, ResolutionContext context)
            {
                var list = new HashSet<string>();
                if (!String.IsNullOrWhiteSpace(sourceMember))
                {
                    sourceMember = sourceMember.Trim();
                    foreach (var item in sourceMember.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Distinct())
                    {
                        list.Add(item);
                    }
                }
                return list;
            }
        }
    }
}